/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package db.JDBC.core;

import db.interfaces.*;
import core.*;
import core.comparators.BookComparator.BOOKCOMPARATORTYPE;
import core.comparators.ComparatorFactory;
import core.comparators.CourseComparator.COURSECOMPARATORTYPE;
import core.comparators.ProgramComparator.PROGRAMCOMPARATORTYPE;
import db.JDBC.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
/**
 *
 * @author Anton
 */
public class CRUDJdbcDAOCore
{
    private static CRUDJdbcDAOCore instance = null;
    private BookDAO bookDAO;
    private CourseDAO courseDAO;
    private ProgramDAO programDAO;
    private SchoolDAO schoolDAO;
    private ShopDAO shopDAO;
    private UserDAO userDAO;


    /**
     * 
     */
    private CRUDJdbcDAOCore()
    {
        JdbcDaoFactory daoFactory = JdbcDaoFactory.getInstance();
        bookDAO = daoFactory.getBookJdbcDao();
        courseDAO = daoFactory.getCourseJdbcDao();
        programDAO = daoFactory.getProgramJdbcDao();
        schoolDAO = daoFactory.getSchoolJdbcDAO();
        shopDAO = daoFactory.getShopJdbcDAO();
        userDAO = daoFactory.getUserJdbcDAO();
    }

    /**
     * 
     * @return
     */
    public static CRUDJdbcDAOCore getInstance()
    {
        if(instance == null)
            instance = new CRUDJdbcDAOCore();
        return instance;
    }

    /**
     * 
     * @param id
     * @return
     */
    public Book getBook(long id)
    {
        return bookDAO.getBookById(id);
    }
    /**
     * 
     * @param book
     */
    public void addBook(Book book)
    {
        if(book == null)
            return;
        bookDAO.addBook(book);
    }
    /**
     * 
     * @param book
     */
    public void updateBook(Book book)
    {
        if(book == null)
            return;
        bookDAO.editBook(book);
    }
    /**
     * 
     * @param book
     */
    public void deleteBook(Book book)
    {
        if(book == null)
            return;
        bookDAO.deleteBook(book);
    }

    /**
     * 
     * @param id
     * @return
     */
    public Course getCourse(long id)
    {
        Course course = courseDAO.getCourseById(id);
        Collection<Book> books = bookDAO.getAllBooksInCourse(course);
        if(course != null && books != null)
        {  
            List<Book> returnBooks = new ArrayList<Book>();
            for(Book b : books)
            {
                if(b != null)
                    returnBooks.add(getBook(b.getId()));
            }
            Collections.sort(returnBooks, ComparatorFactory.getBookComparator(BOOKCOMPARATORTYPE.TITLE, true));
            course.setBooks(returnBooks);            
        }
        return course;
    }
    /**
     * 
     * @param course
     */
    public void addCourse(Course course)
    {
        if(course == null)
            return;
        courseDAO.addCourse(course);
        if(course.getBooks() == null)
            return;
        for (Iterator<Book> iterB = course.getBooks().iterator(); iterB.hasNext(); )
        {            
            Book b = iterB.next();
            if(b != null)
                addBookToCourse(course, b);             
        }
    }
    /**
     * 
     * @param course
     */
    public void updateCourse(Course course)
    {
        if(course == null)
            return;
        Course coursePre = getCourse(course.getId());
        if(coursePre == null || !courseDAO.containsCourse(course))
        {
            addCourse(course);
            return;
        }

        courseDAO.editCourse(course);
        Collection<Book> booksPost = course.getBooks();
        Collection<Book> booksPre = coursePre.getBooks();   
        if(booksPre != null)
        {
            for (Iterator<Book> iterBPre = booksPre.iterator(); iterBPre.hasNext(); )
            {
                Book bookPre = iterBPre.next();
                if(booksPost != null)
                {
                    for (Iterator<Book> iterBPost = booksPost.iterator(); iterBPost.hasNext(); )
                    {
                        Book bookPost = iterBPost.next();

                        if(bookPre != null && bookPost != null &&
                                (bookPre.getIsbn10() != null && bookPre.getIsbn10().equals(bookPost.getIsbn10())))
                        {
                            bookPost.setId(bookPre.getId());
                            updateBook(bookPost);
                            iterBPre.remove();
                            iterBPost.remove();
                        }
                     }
                }
            }
            if(booksPre != null)
                for(Book b : booksPre)
                    deleteBookFromCourse(course, b);
            if(booksPost != null)
                for(Book b : booksPost)
                    addBookToCourse(course, b);
            Collection<Book> setBooks = new ArrayList<Book>();
            for(Book b : bookDAO.getAllBooksInCourse(course))
                if(b!= null)
                    setBooks.add(getBook(b.getId()));
            course.setBooks(setBooks);
        }
    }
    /**
     * 
     * @param course
     */
    public void deleteCourse(Course course)
    {
        if(course == null)
            return;
        courseDAO.deleteCourse(course);
        if(course.getBooks() == null)
            return;
        for (Iterator<Book> iterB = course.getBooks().iterator(); iterB.hasNext(); )
        {
            Book b = iterB.next();
            if(b != null)
                deleteBookFromCourse(course, b);            
        }                
    }
        /**
     *
     * @param course
     * @param book
     */
    public void addBookToCourse(Course course, Book book)
    {
        if(course == null || book == null)
            return;        
        if(!bookDAO.containsBook(book))
            addBook(book);
        courseDAO.addBookToCourse(course, book);
        //course.addBook(book);
    }
    /**
     *
     * @param course
     * @param book
     */
    public void deleteBookFromCourse(Course course, Book book)
    {
        if(course == null || book == null)
            return;
        courseDAO.deleteBookFromCourse(course, book);
        if(!bookDAO.bookIsBound(book))
            deleteBook(book);
        //course.removeBook(book);
    }

    /**
     * 
     * @param id
     * @return
     */
    public Program getProgram(long id)
    {
        Program program = programDAO.getProgramById(id);
        Collection<Course> courses = courseDAO.getAllCoursesInProgram(program);
        if(program != null && courses != null)
        {
            List<Course> returnCourses = new ArrayList<Course>();
            for(Course c : courses)
            {
                if(c != null)
                    returnCourses.add(getCourse(c.getId()));
            }
            Collections.sort(returnCourses, ComparatorFactory.getCourseComparator(COURSECOMPARATORTYPE.NAME, true));
            program.setCourses(returnCourses);
        }
        return program;
    }
    /**
     * 
     * @param program
     */
    public void addProgram(Program program)
    {
        if(program == null)
            return;
        programDAO.addProgram(program);
        if(program.getCourses() == null)
            return;
        for (Iterator<Course> iterC = program.getCourses().iterator(); iterC.hasNext(); )
        {
            Course c = iterC.next();
            if(c != null)
                addCourseToProgram(program, c);
        }
    }
    /**
     * 
     * @param program
     */
    public void updateProgram(Program program)
    {
        if(program == null)
            return;
        Program programPre = getProgram(program.getId());
        if(programPre == null || !programDAO.containsProgram(program))
        {
            addProgram(program);
            return;
        }

        programDAO.editProgram(program);
        Collection<Course> coursesPost = program.getCourses();
        Collection<Course> coursesPre = programPre.getCourses();
        if(coursesPre != null)
        {
            for (Iterator<Course> iterCPre = coursesPre.iterator(); iterCPre.hasNext(); )
            {
                Course coursePre = iterCPre.next();
                if(coursesPost != null)
                {
                    for (Iterator<Course> iterCPost = coursesPost.iterator(); iterCPost.hasNext(); )
                    {
                        Course coursePost = iterCPost.next();

                        if(coursePre != null && coursePost != null &&
                                (coursePre.getCourseId() != null && coursePre.getCourseId().equals(coursePost.getCourseId())))
                        {
                            coursePost.setId(coursePre.getId());
                            updateCourse(coursePost);
                            iterCPre.remove();
                            iterCPost.remove();
                        }
                     }
                }
            }
            if(coursesPre != null)
                for(Course c : coursesPre)
                    deleteCourseFromProgram(program, c);
            if(coursesPost != null)
                for(Course c : coursesPost)
                    addCourseToProgram(program, c);
            Collection<Course> setCourses = new ArrayList<Course>();
            for(Course c : courseDAO.getAllCoursesInProgram(program))
                if(c!= null)
                    setCourses.add(getCourse(c.getId()));
            program.setCourses(setCourses);
        }
    }
    /**
     * 
     * @param program
     */
    public void deleteProgram(Program program)
    {
        if(program == null)
            return;
        programDAO.deleteProgram(program);
        if(program.getCourses() == null)
            return;
        for (Iterator<Course> iterC = program.getCourses().iterator(); iterC.hasNext(); )
        {
            Course c = iterC.next();
            if(c != null)
                deleteCourseFromProgram(program, c);
        }
    }
        /**
     *
     * @param program
     * @param course
     */
    public void addCourseToProgram(Program program, Course course)
    {
        if(program == null || course == null)
            return;        
        if(!courseDAO.containsCourse(course))
            addCourse(course);
        programDAO.addCourseToProgram(program, course);
        //program.addCourse(course);
    }
    /**
     *
     * @param program
     * @param course
     */
    public void deleteCourseFromProgram(Program program, Course course)
    {
        if(program == null || course == null)
            return;
        programDAO.deleteCourseFromProgram(program, course);
        if(!courseDAO.courseIsBound(course))
            deleteCourse(course);
        //program.deleteCourse(course);
    }

    /**
     * 
     * @param id
     * @return
     */
    public School getSchool(long id)
    {
        School school = schoolDAO.getSchoolById(id);
        Collection<Program> programs = programDAO.getAllProgramsInSchool(school);        
        Collection<Course> courses = courseDAO.getAllCoursesInSchool(school);
        
        if(school != null && programs != null)
        {
            List<Program> returnPrograms = new ArrayList<Program>();
            for(Program p : programs)
            {
                if(p != null)
                    returnPrograms.add(getProgram(p.getId()));
            }
            Collections.sort(returnPrograms, ComparatorFactory.getProgramComparator(PROGRAMCOMPARATORTYPE.NAME, true));
            school.setPrograms(returnPrograms);
        }
        if(school != null && courses != null)
        {
            List<Course> returnCourses = new ArrayList<Course>();
            for(Course c : courses)
            {
                if(c != null)
                    returnCourses.add(getCourse(c.getId()));
            }
            Collections.sort(returnCourses, ComparatorFactory.getCourseComparator(COURSECOMPARATORTYPE.NAME, true));
            school.setCourses(returnCourses);
        }
        return school;
    }
    /**
     * 
     * @param school
     */
    public void addSchool(School school)
    {
        if(school == null)
            return;
        schoolDAO.addSchool(school);
        if(school.getPrograms() != null)
        {
            for (Iterator<Program> iterP = school.getPrograms().iterator(); iterP.hasNext(); )
            {
                Program p = iterP.next();
                if(p != null)
                    addProgramToSchool(school, p);
            }
        }
        if(school.getCourses() != null)
        {
            for (Iterator<Course> iterC = school.getCourses().iterator(); iterC.hasNext(); )
            {
                Course c = iterC.next();
                if(c != null)
                    addCourseToSchool(school, c);
            }
        }
    }
    /**
     * 
     * @param school
     */
    public void updateSchool(School school)
    {        
        if(school == null)
            return;
        School schoolPre = getSchool(school.getId());
        if(schoolPre == null || !schoolDAO.containsSchool(school))
        {
            addSchool(school);
            return;
        }
        
        schoolDAO.editSchool(school);        
        Collection<Program> programsPost = school.getPrograms();
        Collection<Program> programsPre = schoolPre.getPrograms();
        long startTime = System.currentTimeMillis();
        if(programsPre != null)
        {
            for (Iterator<Program> iterPPre = programsPre.iterator(); iterPPre.hasNext(); )
            {
                Program programPre = iterPPre.next();
                if(programsPost != null)
                {
                    for (Iterator<Program> iterPPost = programsPost.iterator(); iterPPost.hasNext(); )
                    {
                        Program programPost = iterPPost.next();

                        if(programPre != null && programPost != null &&
                                (programPre.getProgramId() != null && programPre.getProgramId().equals(programPost.getProgramId())))
                        {
                            programPost.setId(programPre.getId());
                            updateProgram(programPost);
                            iterPPre.remove();
                            iterPPost.remove();
                        }
                     }
                }
            }
            if(programsPre != null)
                for(Program p : programsPre)
                    deleteProgramFromSchool(school, p);
            if(programsPost != null)
                for(Program p : programsPost)
                    addProgramToSchool(school, p);  
            Collection<Program> setPrograms = new ArrayList<Program>();
            for(Program p : programDAO.getAllProgramsInSchool(school))
                if(p!= null)
                    setPrograms.add(getProgram(p.getId()));
            school.setPrograms(setPrograms);
        }
        long stopTime = System.currentTimeMillis();
            System.out.println("Edit programs in school in db, time was " + (stopTime - startTime) + " miliseconds.");

        Collection<Course> coursesPost = school.getCourses();
        Collection<Course> coursesPre = schoolPre.getCourses();
        if(coursesPre != null)
        {
            for (Iterator<Course> iterCPre = coursesPre.iterator(); iterCPre.hasNext(); )
            {
                Course coursePre = iterCPre.next();
                if(coursesPost != null)
                {
                    for (Iterator<Course> iterCPost = coursesPost.iterator(); iterCPost.hasNext(); )
                    {
                        Course coursePost = iterCPost.next();

                        if(coursePre != null && coursePost != null &&
                                (coursePre.getCourseId() != null && coursePre.getCourseId().equals(coursePost.getCourseId())))
                        {
                            coursePost.setId(coursePre.getId());
                            updateCourse(coursePost);
                            iterCPre.remove();
                            iterCPost.remove();
                        }
                     }
                }
            }
            if(coursesPre != null)
                for(Course c : coursesPre)
                    deleteCourseFromSchool(school, c);
            if(coursesPost != null)
                for(Course c : coursesPost)
                    addCourseToSchool(school, c);
            Collection<Course> setCourses = new ArrayList<Course>();
            for(Course c : courseDAO.getAllCoursesInSchool(school))
                if(c!= null)
                    setCourses.add(getCourse(c.getId()));
            school.setCourses(setCourses);
        }
        
    }
    /**
     * 
     * @param school
     */
    public void deleteSchool(School school)
    {
        if(school == null)
            return;
        schoolDAO.deleteSchool(school);
        if(school.getPrograms() != null)
        {
            for (Iterator<Program> iterP = school.getPrograms().iterator(); iterP.hasNext(); )
            {
                Program p = iterP.next();
                if(p != null)
                    deleteProgramFromSchool(school, p);
            }
        }
        if(school.getCourses() != null)
        {
            for (Iterator<Course> iterC = school.getCourses().iterator(); iterC.hasNext(); )
            {
                Course c = iterC.next();
                if(c != null)
                    deleteCourseFromSchool(school, c);
            }
        }
    }
    public void addProgramToSchool(School school, Program program)
    {
        if(school == null || program == null)
            return;
        
        if(!programDAO.containsProgram(program))
            addProgram(program);
        schoolDAO.addProgramToSchool(school, program);
        //school.addProgram(program);
    }
    /**
     *
     * @param school
     * @param program
     */
    public void deleteProgramFromSchool(School school, Program program)
    {
        if(school == null || program == null)
            return;

        schoolDAO.deleteProgramFromSchool(school, program);
        if(!programDAO.programIsBound(program))
            deleteProgram(program);
        //school.removeProgram(program);
    }

    /**
     *
     * @param school
     * @param course
     */
    public void addCourseToSchool(School school, Course course)
    {
        if(school == null || course == null)
            return;        
        if(!courseDAO.containsCourse(course))
            addCourse(course);
        schoolDAO.addCourseToSchool(school, course);
        //school.addCourse(course);
    }
    /**
     *
     * @param school
     * @param course
     */
    public void deleteCourseFromSchool(School school, Course course)
    {
        if(school == null || course == null)
            return;
        schoolDAO.deleteCourseFromSchool(school, course);
        if(!courseDAO.courseIsBound(course))
            deleteCourse(course);
        //school.removeCourse(course);
    }

    /**
     * 
     * @param id
     * @return
     */
    public Shop getShop(long id)
    {
        return shopDAO.getShopById(id);
    }
    /**
     * 
     * @param shop
     */
    public void addShop(Shop shop)
    {
        if(shop == null)
            return;
        shopDAO.addShop(shop);
    }
    /**
     * 
     * @param shop
     */
    public void updateShop(Shop shop)
    {
        if(shop == null)
            return;
        shopDAO.editShop(shop);
    }
    /**
     * 
     * @param shop
     */
    public void deleteShop(Shop shop)
    {
        if(shop == null)
            return;
        shopDAO.deleteShop(shop);
    }

    /**
     * 
     * @param id
     * @return
     */
    public User getUser(long id)
    {
        User user = userDAO.getUserByUserId(id);
        Collection<Program> programs = programDAO.getAllProgramsInUser(user);        
        Collection<Course> courses = courseDAO.getAllCoursesInUser(user);

        if(programs != null)
        {
            List<Program> returnPrograms = new ArrayList<Program>();
            for(Program p : programs)
            {
                returnPrograms.add(getProgram(p.getId()));
            }
            Collections.sort(returnPrograms, ComparatorFactory.getProgramComparator(PROGRAMCOMPARATORTYPE.NAME, true));
            user.setPrograms(returnPrograms);
        }
        if(courses != null)
        {
            List<Course> returnCourses = new ArrayList<Course>();
            for(Course c : courses)
            {
                returnCourses.add(getCourse(c.getId()));
            }
            Collections.sort(returnCourses, ComparatorFactory.getCourseComparator(COURSECOMPARATORTYPE.NAME, true));
            user.setCourses(returnCourses);
        }
        return user;
    }
    /**
     * 
     * @param user
     */
    public void addUser(User user)
    {
        if(user == null)
            return;
        userDAO.addUser(user);
    }
    /**
     * 
     * @param user
     */
    public void updateUser(User user)
    {
        if(user == null)
            return;
        userDAO.editUser(user);
    }
    /**
     * 
     * @param user
     */
    public void deleteUser(User user)
    {
        if(user == null)
            return;
        userDAO.deleteUser(user);
    }
}
